{
 "cells": [
  {
   "cell_type": "code",
   "id": "initial_id",
   "metadata": {
    "collapsed": true,
    "ExecuteTime": {
     "end_time": "2025-10-10T07:41:51.071139Z",
     "start_time": "2025-10-10T07:41:30.026791Z"
    }
   },
   "source": [
    "import copy\n",
    "import json\n",
    "import ssl\n",
    "import time\n",
    "import websocket\n",
    "\n",
    "\n",
    "class OrderBook(object):\n",
    "\n",
    "    BIDS = 'bid'\n",
    "    ASKS = 'ask'\n",
    "\n",
    "    def __init__(self, limit=20):\n",
    "\n",
    "        self.limit = limit\n",
    "\n",
    "        # (price, amount)\n",
    "        self.bids = {}\n",
    "        self.asks = {}\n",
    "\n",
    "        self.bids_sorted = []\n",
    "        self.asks_sorted = []\n",
    "\n",
    "    def insert(self, price, amount, direction):\n",
    "        if direction == self.BIDS:\n",
    "            if amount == 0:\n",
    "                if price in self.bids:\n",
    "                    del self.bids[price]\n",
    "            else:\n",
    "                self.bids[price] = amount\n",
    "        elif direction == self.ASKS:\n",
    "            if amount == 0:\n",
    "                if price in self.asks:\n",
    "                    del self.asks[price]\n",
    "            else:\n",
    "                self.asks[price] = amount\n",
    "        else:\n",
    "            print('WARNING: unknown direction {}'.format(direction))\n",
    "\n",
    "    def sort_and_truncate(self):\n",
    "        # sort\n",
    "        self.bids_sorted = sorted([(price, amount) for price, amount in self.bids.items()], reverse=True)\n",
    "        self.asks_sorted = sorted([(price, amount) for price, amount in self.asks.items()])\n",
    "\n",
    "        # truncate\n",
    "        self.bids_sorted = self.bids_sorted[:self.limit]\n",
    "        self.asks_sorted = self.asks_sorted[:self.limit]\n",
    "\n",
    "        # copy back to bids and asks\n",
    "        self.bids = dict(self.bids_sorted)\n",
    "        self.asks = dict(self.asks_sorted)\n",
    "\n",
    "    def get_copy_of_bids_and_asks(self):\n",
    "        return copy.deepcopy(self.bids_sorted), copy.deepcopy(self.asks_sorted)\n",
    "\n",
    "\n",
    "class Crawler:\n",
    "    def __init__(self, symbol, output_file):\n",
    "        self.orderbook = OrderBook(limit=10)\n",
    "        self.output_file = output_file\n",
    "\n",
    "        self.ws = websocket.WebSocketApp('wss://api.gemini.com/v1/marketdata/{}'.format(symbol),\n",
    "                                         on_message = lambda ws, message: self.on_message(message))\n",
    "        self.ws.run_forever(sslopt={'cert_reqs': ssl.CERT_NONE})\n",
    "\n",
    "    def on_message(self, message):\n",
    "        # 对收到的信息进行处理，然后送给 orderbook\n",
    "        data = json.loads(message)\n",
    "        for event in data['events']:\n",
    "            price, amount, direction = float(event['price']), float(event['remaining']), event['side']\n",
    "            self.orderbook.insert(price, amount, direction)\n",
    "\n",
    "        # 整理 orderbook，排序，只选取我们需要的前几个\n",
    "        self.orderbook.sort_and_truncate()\n",
    "\n",
    "        # 输出到文件\n",
    "        with open(self.output_file, 'a+') as f:\n",
    "            bids, asks = self.orderbook.get_copy_of_bids_and_asks()\n",
    "            output = {\n",
    "                'bids': bids,\n",
    "                'asks': asks,\n",
    "                'ts': int(time.time() * 1000)\n",
    "            }\n",
    "            f.write(json.dumps(output) + '\\n')\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    crawler = Crawler(symbol='BTCUSD', output_file='BTCUSD.txt')"
   ],
   "outputs": [],
   "execution_count": 1
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-10T07:40:58.253730Z",
     "start_time": "2025-10-10T07:40:58.252481Z"
    }
   },
   "cell_type": "code",
   "source": "",
   "id": "4935d91e7e3322fb",
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": "",
   "id": "dcb40608cfa42877"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
